#include "Altavoz.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

using std::cout;
using std::cerr;
using std::endl;

Altavoz::Altavoz() :
	DispositivoAudio() {
	int ret;
	unsigned int val;
	Decodificador = new Deco_Audio();
	Decodificador->register_codecs();
	// Abro el dispositivo
	ret = snd_pcm_open(&this->handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
	if (ret < 0) {
		cerr << "no se pudo abrir el dispositivo pcm: " << snd_strerror(ret) << endl;
		exit(1);
	}
	// Allocate a hardware parameters object
	snd_pcm_hw_params_alloca(&this->params);
	// Valores por defecto
	snd_pcm_hw_params_any(this->handle, this->params);
	// modo interleaved
	snd_pcm_hw_params_set_access(this->handle, this->params,
			SND_PCM_ACCESS_RW_INTERLEAVED);
	// Formato signed 16-bit little-endian
	snd_pcm_hw_params_set_format(this->handle, this->params,
			SND_PCM_FORMAT_S16_LE);
	// Seteo cantidad de canales
	snd_pcm_hw_params_set_channels(this->handle, this->params, this->canales);
	val = 44100; // bits/segundo sampling rate (calidad CD)
	snd_pcm_hw_params_set_rate_near(this->handle, this->params, &val,
			&this->dir);
	snd_pcm_hw_params_set_period_size_near(this->handle, this->params,
			&this->frames, &this->dir);
	// Cargo los parametros al driver
	ret = snd_pcm_hw_params(this->handle, this->params);
	if (ret < 0) {
		cerr << "no se pudieron setear los parametros del hardware: " << snd_strerror(ret) << endl;
		exit(1);
	}
	// Tamanio del periodo
	snd_pcm_hw_params_get_period_size(this->params, &this->frames, &this->dir);

	Decodificador->busca_codec();

	Decodificador->ini_contexto();

	Decodificador->abre_codec();
}

int Altavoz::ejecutar(uint8_t* buffer, int tam_arg) {
	static short* aux;   // Puntero auxiliar
	static int faltan;   // Frames que faltan para completar un periodo
	static int ret, len = 0, size_FrameDecodificado = 0;
	static int aux_size;
	size_FrameDecodificado = AVCODEC_MAX_AUDIO_FRAME_SIZE;
	static AVPacket packet;
	static uint8_t* FrameDecodificado = new uint8_t[size_FrameDecodificado];
	av_init_packet(&packet);
	packet.size = 0;

	packet.size = tam_arg;
	packet.data = buffer;
	while (packet.size >= 209) {
		size_FrameDecodificado = AVCODEC_MAX_AUDIO_FRAME_SIZE;
		len = Decodificador->decodificar((short**) &FrameDecodificado,
				&size_FrameDecodificado, &packet);
		if (len < 0) {
			cerr << "Error decodificando" << endl;
			break;
		}
		if (size_FrameDecodificado > 0) {
			aux = (short*) FrameDecodificado;
			faltan = size_FrameDecodificado / 4;
			while (faltan > 0) {
				ret = snd_pcm_writei(handle, aux, faltan);
				if (ret == -EAGAIN)
					continue;
				if (ret < 0) {
					if (this->recuperacion(ret) < 0) {
						cerr << "speaker: error al escribir: " << snd_strerror(
								ret) << endl;
						exit( EXIT_FAILURE);
					}
					break; // Descarto el periodo
				}
				if (ret == 0) {
					cerr << "fin de archivo" << endl;
					break;
				}
				if (ret == -EPIPE) {
					// EPIPE = underrun
					cerr << "altavoz: underrun" << endl;
					snd_pcm_prepare( handle);
				}
				aux += ret;
				faltan -= ret;
			}
		}
		packet.size -= len;
		packet.data += len;
	}
	aux_size = packet.size;

//	delete[] FrameDecodificado;
	av_free_packet(&packet);
	return aux_size;
}

Altavoz::~Altavoz() {
	snd_pcm_drain(handle);
	snd_pcm_close(handle);
	delete Decodificador;
}
